//This file contains the class SettingsManager
//SettingsManager provides a pure static access to a map of dators
//This map of dators can be modified in the following way:
// * Registering a new variable -- RegisterVariable()
// * Setting the value of a variable -- SetVariable()
// * Loading values from file -- ParseIniFile(), ParseXmlFile()
//     -- File syntax demonstration can be found at each of these
//        two function declarations below.
//     -- Settings found in files will be name mangled
//
//Note: loading a settins file will NOT register new variables,
//only set the values of existing ones.


#ifndef ENGINE_SETTINGS_MANAGER_H
#define ENGINE_SETTINGS_MANAGER_H

#include <string>
#include <map>
#include <fstream>
#include <exception>

#include <boost/shared_ptr.hpp>

#include "base/types.h"
#include "base/function_not_implemented_exception.h"
#include "base/result_codes.h"
#include "tinyxml/tinyxml.h"
#include "tinyxml/tinystr.h"

#include "engine/dator.h"
#include "engine/result_codes.h"

namespace engine {


class SettingsManager {
public:
    //Associate a new dator with a variable_name in the settings map
    //This does not affect the value of the dator
    static int RegisterVariable(const std::string &name, boost::shared_ptr<Dator> &variable);

    //Set the value of a dator already in the settings map
    //This does not insert a new mapping
    static int SetVariable(const std::string &name, const std::string &value);  

    //Set the values of all the dators in the given file
    //Parsing a file will NOT add a dator to the SettingsManager
    //
    //A call to this generic funciton will decide which parsing funciton to use.
    //  * A filename ending in .xml will be parsed using ParseXmlFile()
    //  * Anything else will be parsed using ParseIniFile()
    static int ParseFile(const std::string & filename);
    
    //Example ini syntax
    //
    //  setting1 = value1
    //  [group1]
    //    setting2 = value2
    //    [group2]
    //      setting2 = value3
    //    []
    //    setting3 = value4
    //
    //And results in the following actions:
    //  * SetVariable(setting1, value1)
    //  * SetVariable(group1::setting2, value2);
    //  * SetVariable(group1::group2::setting2, value3);
    //  * SetVariable(group1::setting3, value4);
    //
    //Note: Notice that group1 has no closing [] syntax. This will cause no errors.
    //  including closing [] for group1 would also cause no errors and would have
    //  exact same results. 
    //  Also, whitespace it ignored
    static int ParseIniFile(const std::string & filename);

    //Example XML syntax    
    //  <root>
    //    <setting1>value1</setting1>
    //    <group1>
    //      <setting2>value2</setting2>
    //    </group1>
    //    <setting2>value3</setting3>
    //  </root> 
    //
    //And results in the follwing actions:
    //  * SetVariable(setting1, value1);
    //  * SetVariable(group1::setting2, value2);
    //  * SetVariable(setting2, value2);
    static int ParseXmlFile(const std::string & filename);

    //The following is a publicly accessible means to properly generate group_name paths
    //
    //i.e. create group1::group2:: from group_name = "group2" and path="group1"
    //                                                         or path="group1::"
    //  both examples are valid and have the same output
    static int AppendGroupName(const std::string & group_name, std::string & path);
    
    //The following is a publicly accesible means to Remove the last group name from path
    //That is move up a level in the naming hierarchy
    //
    //i.e. create "group1::" from path = "group1::group2::"
    //i.e. create ""         from path = "group1::setting1"
    static int RemoveLastGroup(std::string & path);
    
    //The following is a publicly accessible means to name mangle settings give a specific group path
    //
    //i.e. create group1::group2::setting1 from name ="setting1" and path = "group1::group2"
    //                                                            or path = "group1::group2::"
    //  both examples are valid and have the same output
    static int ResolveName(const std::string & path, std::string & name);
private:

    //This helper function analyzes a single line from an ini file and determine what to do    
    static int ParseIniLine(const std::string & value, std::string & path);
    
    //This helper function does the recursive work of traversing the xml tree
    static int ParseXmlElement(const TiXmlElement * element, std::string path);

    static std::map<std::string, boost::shared_ptr<Dator> > settings_;
    const static std::string kScopeResolution_;
};

} //namespace engine

#endif //ENGINE_SETTINGS_MANAGER_H